Back to IRIX

Pipeline, May/June 1995, vol.6, no.3
Copyright © 1995 Silicon Graphics


Getting Started With Socket Programming

This article will present an introduction to sockets, an application
programming interface (API) for network applications in a UNIX
environment. Sockets are a UNIX interface to the TCP/IP protocol and
were developed at the University of California at Berkeley.

The example discussed in this article uses a connection-oriented (TCP) client/server model. The programs establish a connection between two systems (or two processes on the same system), and data is passed from the client to the server. The programs are designed to be very simple and straightforward and follow the flow of the diagram in Figure 1.

         Server                                  Client

       --------------                        --------------
       | create a   |                        |  create a  |
       | socket     |                        |  socket    |
       --------------                        --------------
             |                                     |
             |                                     |
             V                                     |
       --------------                              |
       | bind a name|                              |
       | to the     |                              |
       | socket     |                              V
       --------------                        --------------
             |                               | validate   |
             |                               | server's   |
             |                               | host name  |
             V                               --------------
       --------------                              |
       | listen for |                              |
       | incoming   |                              |
       | conection  |                              |
       | request    |                              |
       --------------                              V
             |                               --------------
             |                               | make a     |
             |<------------------------------| connect    |
             V                               | request    |
       --------------                        --------------
       | accept the |                              |
       | connection |                              |
       | request on |                              |
       | a new      |                              |
       | socket     |                              V
       --------------                        --------------
             |<------------------------------| write to   |
             V                               | the socket |
       --------------                        --------------
       | read data  |                              |
       | sent to    |                              |
       | the socket |                              |
       --------------                              |
             |                                     |
             |                                     |
             V                                     V

           Exit                                  Exit

Figure 1. Connection oriented client/server model
The first step in creating a connection is to create a socket(2). A socket is defined as the endpoint of communication. An endpoint is only half of a connection, so two sockets will need to be created; one each for the client and server. Another way to look at this is to regard the socket connection between two processes as a bidirectional pipe. The processes may exist on the same system, or on two separate systems.

When a socket is created, parameters indicating the communications domain and the type of socket that will be utilized must be specified. This example will use the 32-bit Internet address protocol (AF_INET), and a connection-oriented (stream) socket (SOCK_STREAM). (Refer to the manual page for socket(2) and /usr/include/sys/sockets.h for more information.)

sock = socket(AF_INET, SOCK_STREAM, 0); 
	if (sock < 0) 
	{ 
		perror("opening stream socket"); 
		exit(1); 
	}
Note that it is always good programming practice to include some way of determining if an error occurs.

When a socket is created, it has no name. Until a name is bound to a socket, processes have no way to reference it. On the server, the bind(2) system call assigns a name to the newly created socket. Note that this actually only specifies half of the connection (remember, a socket is only half of a connection). The connect(2) system call (on the client), and the accept(2) system call (on the server) are used to complete the association.

Server and Client Interaction

Figure 1 provides a relatively straightforward block diagram of how the server and client programs interact. First, a socket is opened on both the server and the client. On the server, a name is bound to the socket, and the server begins listening for a connection request. The server will continue to listen until a connection request is received from the client. When a connection indication is received, the server creates a new transport endpoint (socket) and accepts the client's data on that endpoint.

The sample programs at the end of this article (server.c and client.c) provide the code that follows the block diagram presented in Figure 1. On the client side, after the socket has been opened, a connection must be made to the server. However, first the server must be identified. One common way to identify the server is to use its Internet host name. The library function gethostbyname(3N) can be used to obtain the IP address of the host by searching the NIS database, querying the BIND name server, or searching the file /etc/hosts. If the hostname cannot be identified an error message is returned. If a hostname is identified, its Internet address is provided.

The client takes the information provided by gethostbyname, assigns a port number, and attempts to connect to the server using the connect system call. The connect system call includes the local socket as well as the socket the client wishes to connect with. If the connect system call on the client, and the accept system call on the server are successful, a connection will be made between the client and server.

Once a connection has been established, data can be written or read by either process. In this example, the string "Hello server" is written to the socket by the client, read by the server, and then written to standard out. Both programs then exit.

The server program presented in this example is an iterative server in that each connection request must be handled in sequence. In many server programs, the server will use the system call fork(2) to create a child process. The child process will then create the new socket associated with the accept system call, and the server parent process will return to listening for additional connection requests. This is known as a concurrent server.

References

For other examples of socket programs including advanced features such as socket options, refer to the /usr/people/4Dgifts/examples/network directory, provided as part of the 4Dgifts.src.full subsystem on the IDO (IRIX Developer's Option) CD-ROM.

Additional documentation is available in the IRIX Network Programming Guide, available on-line with InSight(1).

The resources listed below are only a subset of those currently available on network programming. The presence or absence of any particular resource should not be construed as a comment on its usefulness.

Leffler, S., McKusick, M., Karels, M., and Quarterman, J., 1989, The Design and Implementation of the 4.3BSD UNIX Operating System, Addison-Wesley, Reading MA, ISBN 0-201-06196-1.

Rieken, B., and Weiman, L., 1992, Adventures in UNIX Network Applications Programming, John Wiley and Sons, New York, New York, ISBN 0-471-52858-7.

Stevens, Richard W., 1990, UNIX Network Programming, Prentice Hall, Englewood Cliffs, New Jersey, ISBN 0-13- 949876-1.




The following programs are broken out
as C source along with a Makefile in
toolbox/src/exampleCode/irix/sockets.


/* 	server.c 
	To compile: cc server.c -o server 
	To run: type "server" in a window
	Note: the server must be started first.
*/

#include <sys/types.h> 
#include <sys/socket.h> 
#include <netinet/in.h> 
#include <netdb.h> 
#include <stdio.h>

#define SRV_PORT 5400

main(argc, argv) 
int argc; 
char *argv[]; 
{ 
	int sock; 
	struct sockaddr_in server; 
	int msgsock; 
	char buf[15]; 

	/* create a socket */ 

	sock = socket(AF_INET, SOCK_STREAM, 0); 
	if ( sock < 0) 
	{ 
		perror("opening stream socket"); 
		exit(1); 
	}
	server.sin_family = AF_INET;
	server.sin_addr.s_addr = INADDR_ANY; 

	/*	The constant INADDR_ANY tells the system 
		that we will accept a connection on any 
		Internet interface on the system. 
	*/

	/* 	Assign server port number */ 
	server.sin_port = SRV_PORT; 

	/* 	name the socket */
	if (bind(sock, (struct sockaddr *)&server, \
		sizeof server) < 0 ) 
	{ 
		perror("binding stream socket"); 
		exit(1); 
	} 

	/* 	confirm that we are in listen mode */
	printf("Waiting for connect request\n"); 
	if (listen(sock, 5) < 0 ) 
	{ 
		perror("listen error"); 
		exit(1); 
	}
	for (;;) /* loop waiting for connect */ 
	{ 
	int newsock, len = sizeof ( server ); 
	newsock = accept(sock, (struct \
		sockaddr *)&server, &len); 
	if (newsock < 0 ) 
		{ 
			perror("accept error"); 
			exit(1); 
		} 

	printf("CONNECTION ESTABLISHED, \
		GOOD WORK!\n"); 

	/* 	read data sent to the socket, 
		or indicate an error 
	*/
	if (read(newsock, buf, sizeof(buf)) < 0 ) 
		{ 
			perror("read error"); 
			exit(1); 
		} 
	write(1, buf, sizeof(buf)); 
	printf("Bye\n"); 
	exit(); 
	} 
}

/* 	client.c 
	To compile: cc client.c -o client 
	To run: client <host-name> in a window 
		Where <host-name> is any reachable host 
*/

#include <sys/types.h> 
#include <sys/socket.h> 
#include <netinet/in.h> 
#include <netdb.h> 
#include <stdio.h>

#define CLN_PORT 5400

main(argc, argv) 
int argc; 
char *argv[]; 
{ 
	int sd; 
	char buf[15] = "Hello server\n"; 
	struct sockaddr_in server; 
	struct hostent *hp, *gethostbyname();

	/* 	create a socket */
	sd = socket(AF_INET, SOCK_STREAM, 0); 
	if ( sd < 0) 
		{ 
			perror("opening stream socket"); 
			exit(1); 
		}

	/* 	Connect socket using hostname provided 
		in command line 
	*/ 
	server.sin_family = AF_INET; 
	hp = gethostbyname(argv[1]); 
	if (hp == 0) 
		{ 
			fprintf(stderr, "%s: unknown host, \
				enter valid host name\n", argv[1]); 
			exit(1); 
		} 
	memcpy((char *)&server.sin_addr, \
		(char *)hp ->h_addr, hp->h_length ); 
	/* 	Assign client port number */
	server.sin_port = CLN_PORT; 

	/* 	Here we go, lets try to connect */ 
	if (connect(sd, (struct \
		sockaddr *)&server, sizeof server ) < 0 ) 
		{ 
			perror("connecting stream socket"); 
			exit(1); 
		} 
	printf("Connected\n"); 

	/* 	write the character string to the socket 
		and indicate an error if unsuccessful 
	*/ 
	if (write(sd, buf, sizeof(buf)) < 0) 
		{ 
			perror("writing"); 
			exit(1); 
		} 

}